<script>
export default {
  name: "index"
}
</script>

<template>
  <div class="mj-container">
    <div class="left-panel">
      <h1 class="page-title">Midjourney</h1>
      <div class="input-section">
        <div class="prompt-input">
          <el-input
            type="textarea"
            v-model="prompt"
            :autosize="{ minRows: 3, maxRows: 6 }"
            placeholder="请输入图片描述（必须是英文），例如：mysterious a figure from behind"
            @keydown.enter.native.prevent="handleEnterKey"
            class="custom-input"
          ></el-input>
        </div>

        <div class="options-panel">
          <div class="option-group">
            <div class="option-title">图片比例</div>
            <div class="size-options">
              <div
                v-for="option in aspectRatioOptions"
                :key="option.value"
                class="size-option"
                :class="{ 'is-active': selectedAspectRatio === option.value }"
                @click="selectedAspectRatio = option.value"
              >
                {{ option.label }}
              </div>
            </div>
          </div>

          <div class="option-group">
            <div class="option-title">模型版本</div>
            <div class="style-options">
              <div
                v-for="option in modelVersionOptions"
                :key="option.value"
                class="style-option"
                :class="{ 'is-active': selectedModelVersion === option.value }"
                @click="selectedModelVersion = option.value"
              >
                {{ option.label }}
              </div>
            </div>
          </div>
        </div>

        <div class="options-panel">
          <div class="option-group">
            <div class="option-title">画质 (--q {{ selectedQuality }})</div>
            <el-slider
              v-model="selectedQuality"
              :min="0"
              :max="1"
              :step="0.1"
              show-stops
            ></el-slider>
          </div>

          <div class="option-group">
            <div class="option-title">艺术程度 (--s {{ selectedStyleLevel }})</div>
            <el-slider
              v-model="selectedStyleLevel"
              :min="0"
              :max="1000"
              :step="100"
              show-stops
            ></el-slider>
          </div>

          <div class="option-group">
            <div class="option-title">随机性 (--chaos {{ selectedChaos }})</div>
            <el-slider
              v-model="selectedChaos"
              :min="0"
              :max="100"
              :step="10"
              show-stops
            ></el-slider>
          </div>
        </div>

        <div class="options-panel">
          <div class="option-group">
            <div class="option-title">模式选择</div>
            <div class="size-options">
              <div
                v-for="option in modeOptions"
                :key="option.value"
                class="size-option"
                :class="{ 'is-active': selectedMode === option.value }"
                @click="selectedMode = option.value"
              >
                {{ option.label }}
              </div>
            </div>
          </div>

          <div class="option-group">
            <div class="option-title">上传垫图</div>
            <FileUpload v-model="baseImages" :multiple="true"/>
          </div>
        </div>
      </div>

      <div class="button-group">
        <el-button
          type="primary"
          @click="generateImage"
          :loading="isGenerating"
          :disabled="!prompt.trim()"
          class="generate-btn"
        >
          生成图片
        </el-button>
      </div>
    </div>

    <div class="right-panel">
      <div class="chat-window">
        <div class="messages" ref="messagesContainer">
          <div v-for="(message, index) in messages" :key="index" class="message-item" :class="message.role">
            <template v-if="message.role === 'image'">
              <div class="image-container">
                <el-image
                  :src="message.content"
                  fit="contain"
                  :preview-src-list="[message.content]"
                >
                  <template #placeholder>
                    <div class="image-placeholder">
                      <i class="el-icon-picture-outline"></i>
                    </div>
                  </template>
                </el-image>

                <div class="image-actions" v-if="message.buttons && message.buttons.length">
                  <div class="action-buttons">
                    <div class="action-row">
                      <el-button
                        v-for="button in message.buttons.filter(b => b.label.startsWith('U'))"
                        :key="button.customId"
                        size="mini"
                        @click="handleButtonAction(button, message.taskId)"
                      >
                        {{ button.label }}
                      </el-button>
                    </div>
                    <div class="action-row">
                      <el-button
                          v-for="button in message.buttons.filter(b => b.label.startsWith('V'))"
                          :key="button.customId"
                          size="mini"
                          @click="handleButtonAction(button, message.taskId)"
                      >
                        {{ button.label }}
                      </el-button>
                      <el-button
                          v-for="button in message.buttons.filter(b => b.emoji === '🔄')"
                          :key="button.customId"
                          size="mini"
                          @click="handleButtonAction(button, message.taskId)"
                      >
                        🔄
                      </el-button>
                    </div>
                    <div class="action-row">
                      <el-button
                          v-for="button in message.buttons.filter(b => b.label.startsWith('Upscale'))"
                          :key="button.customId"
                          size="mini"
                          @click="handleButtonAction(button, message.taskId)"
                      >
                        {{ button.emoji }}
                        {{ button.label }}
                      </el-button>
                    </div>
                    <div class="action-row">
                      <el-button
                          v-for="button in message.buttons.filter(b => b.label.startsWith('Vary'))"
                          :key="button.customId"
                          size="mini"
                          @click="handleButtonAction(button, message.taskId)"
                      >
                        {{ button.emoji }}
                        {{ button.label }}
                      </el-button>
                    </div>
                    <div class="action-row">
                      <el-button
                          v-for="button in message.buttons.filter(b => b.label.startsWith('Zoom'))"
                          :key="button.customId"
                          size="mini"
                          @click="handleButtonAction(button, message.taskId)"
                      >
                        {{ button.emoji }}
                        {{ button.label }}
                      </el-button>
                    </div>
                  </div>
                </div>
              </div>
              <div class="prompt-text">ID.{{ message.id}} {{ message.prompt }}</div>
            </template>
            <template v-else>
              <div class="text-content"> {{ message.content }}</div>
            </template>
          </div>
        </div>

        <div class="empty-state" v-if="messages.length === 0">
          <i class="el-icon-picture-outline"></i>
          <p v-if="isGenerating">正在生成图像...</p>
          <p v-else>选择左侧选项并点击生成按钮开始创作</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import FileUpload from "@/components/FileUpload.vue";
import axios from "axios";
import {http} from "@/api";

export default {
  name: 'MidjourneyView',
  components: { FileUpload },
  data() {
    return {
      conversationId: '',
      prompt: '',
      baseImages: '',
      isGenerating: false,
      selectedAspectRatio: '16:9',
      selectedModelVersion: '5.2',
      selectedQuality: 1,
      selectedStyleLevel: 100,
      selectedChaos: 7,
      selectedMode: 'fast',
      currentTaskId: null,
      pollingInterval: null,
      messages: [],

      aspectRatioOptions: [
        { label: '1:1', value: '1:1' },
        { label: '4:3', value: '4:3' },
        { label: '3:4', value: '3:4' },
        { label: '16:9', value: '16:9' },
        { label: '9:16', value: '9:16' }
      ],
      modelVersionOptions: [
        { label: 'v5.1', value: '5.1' },
        { label: 'v5.2', value: '5.2' },
        { label: 'v6', value: '6' },
        { label: 'v6.1', value: '6.1' }
      ],
      modeOptions: [
        { label: '快速', value: 'fast' },
        { label: '放松', value: 'relax' }
      ],
      fetchLoading: false,

      isLoading: false,
      page: 0,
      pageSize: 10,
      total: 0,
      isLoadingMore: false,
      noMore: false,
    }
  },
  async created() {
    this.conversationId = this.$route.query.conversationId;
    if (this.conversationId) {
      await this.loadMessages()
      this.scrollToBottom()
    }
  },
  computed: {
    fullPrompt() {
      let prompt = this.prompt.trim();

      // Add aspect ratio
      if (this.selectedAspectRatio) {
        prompt += ` --ar ${this.selectedAspectRatio}`;
      }

      // Add model version
      if (this.selectedModelVersion) {
        prompt += ` --v ${this.selectedModelVersion}`;
      }

      // Add quality
      prompt += ` --q ${this.selectedQuality}`;

      // Add style level
      prompt += ` --s ${this.selectedStyleLevel}`;

      // Add chaos
      prompt += ` --chaos ${this.selectedChaos}`;

      return prompt;
    }
  },
  methods: {
    handleEnterKey(e) {
      if (e.shiftKey) {
        const textarea = e.target;
        const start = textarea.selectionStart;
        const end = textarea.selectionEnd;
        const value = textarea.value;

        this.prompt = value.substring(0, start) + '\n' + value.substring(end);

        this.$nextTick(() => {
          textarea.selectionStart = textarea.selectionEnd = start + 1;
        });
      } else {
        this.generateImage();
      }
    },
    // 加载消息列表
    async loadMessages() {
      if (this.isLoadingMore) return
      if (this.noMore) return
      this.isLoadingMore = true
      this.page++;
      try {
        const res = await http.message.page({
          conversation_id: this.conversationId,
          last_message_id: this.messages[0] ? this.messages[0].id : '',
          pageSize: this.pageSize
        })
        console.log(res)
        let { rows, count } = res.data
        rows = rows.map(item => {
          return {
            mode: 'chat',
            ...item,
            showReasoning: false,
            role: item.response ? 'image' : '',
            content: item.response ? item.response.imageUrl : '',
            prompt: item.response ? item.response.prompt : item.content,
            buttons: item.response ? item.response.buttons : [],
            taskId: item.task_id,
            id: item.id
          }
        })
        // 因为是倒序查询，所以新消息要添加到前面
        this.messages = [...rows.reverse(), ...this.messages]
        this.total = count
        this.noMore = this.messages.length >= count
        console.log(this.messages)
      } catch (error) {
        console.error('加载消息失败:', error)
        this.$message.error('加载消息失败')
      } finally {
        this.isLoadingMore = false
      }
    },
    async generateImage() {
      if (!this.prompt.trim()) return;

      this.isGenerating = true;

      try {
        // Prepare the request data
        const requestData = {
          prompt: this.fullPrompt,
          speed: this.selectedMode
        };

        // Add base64 images if available
        if (this.baseImages) {
          requestData.base64Array = this.baseImages.split(',').filter(img => img);
        }
        requestData.conversationId = this.conversationId
        // Add a system message to show the prompt
        this.messages.push({
          role: 'assistant',
          content: `正在生成: ${this.fullPrompt}`
        });

        // Submit the image generation request
        const response = await http.mj.create(requestData)
        if (response.data) {
          this.currentTaskId = response.data.taskId;
          this.startPolling(response.data.taskId);
          // https://file.302ai.cn/gpt/imgs/20250316/90044b4944e04304b9583e50335c05e0.png
          this.messages[this.messages.length -1].content = `正在生成：${response.data.prompt} (0%})`
        } else {
          this.messages.push({
            role: 'error',
            content: '生成请求失败，请重试'
          });
          this.isGenerating = false;
        }
      } catch (error) {
        console.error('Error generating image:', error);
        this.messages.push({
          role: 'error',
          content: `生成失败: ${error.message || '未知错误'}`
        });
        this.isGenerating = false;
      }
    },

    startPolling(taskId) {
      this.stopPolling(); // Clear any existing polling
      this.fetchLoading = false
      this.pollingInterval = setInterval(() => {
        if (!this.fetchLoading) {
          this.checkTaskStatus(taskId);
        }
      }, 5000); // Poll every 3 seconds
    },

    stopPolling() {
      if (this.pollingInterval) {
        clearInterval(this.pollingInterval);
        this.pollingInterval = null;
      }
    },

    async checkTaskStatus(taskId) {
      this.fetchLoading = true
      try {
        const response = await http.mj.fetch({
          taskId: taskId,
          conversationId: this.conversationId,
        })
        const data = response.data;

        // Check if task is completed
        if (data.status === 'SUCCESS') {
          this.stopPolling();
          this.isGenerating = false;
          console.log('data',data)
          // Add the image to messages
          this.messages.push({
            role: 'image',
            content: data.imageUrl,
            prompt: data.prompt,
            buttons: data.buttons,
            taskId: data.id
          });

          // Scroll to the bottom of the chat
          this.$nextTick(() => {
            this.scrollToBottom();
          });
        }
        // Check if task failed
        else if (data.status === 'FAILED') {
          this.stopPolling();
          this.isGenerating = false;

          this.messages.push({
            role: 'error',
            content: `生成失败: ${data.failReason || '未知错误'}`
          });
        }
        // For tasks still in progress, update the progress message
        else if (data.progress) {
          // Find the last system message and update it
          const lastSystemMsgIndex = [...this.messages].reverse().findIndex(msg => msg.role === 'assistant');
          if (lastSystemMsgIndex >= 0) {
            const actualIndex = this.messages.length - 1 - lastSystemMsgIndex;
            this.messages[actualIndex].content = `正在生成: ${data.prompt} (${data.progress})`;
          }
        }
        this.fetchLoading = false
      } catch (error) {
        console.error('Error checking task status:', error);
        // Don't stop polling on error, just log it
        this.fetchLoading = false
      }
    },

    async handleButtonAction(button, taskId) {
      try {
        this.isGenerating = true;

        // Extract action type from customId (e.g., "MJ::JOB::upsample::1::...")
        const parts = button.customId.split('::');
        const actionType = parts[2]; // upsample, variation, reroll
        const index = parts[3]; // 1, 2, 3, 4, or 0 for reroll

        // Prepare the request data
        const requestData = {
          taskId: taskId,
          customId: button.customId,
          action: actionType.toUpperCase(),
          conversationId: this.conversationId
        };

        // Add a system message to show the action
        this.messages.push({
          role: 'system',
          content: `正在${actionType === 'upsample' ? '放大进行修改' : actionType === 'variation' ? '继续生成' : '生成'}图片...`
        });

        // Submit the action request
        const response = await http.mj.action(requestData)

        if (response.data) {
          this.currentTaskId = response.data;
          this.startPolling(response.data);
        } else {
          this.messages.push({
            role: 'error',
            content: '操作请求失败，请重试'
          });
          this.isGenerating = false;
        }
      } catch (error) {
        console.error('Error performing action:', error);
        this.messages.push({
          role: 'error',
          content: `操作失败: ${error.message || '未知错误'}`
        });
        this.isGenerating = false;
      }
    },

    scrollToBottom() {
      if (this.$refs.messagesContainer) {
        this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
      }
    },

    downloadImage(imageUrl) {
      const a = document.createElement('a');
      a.href = imageUrl;
      a.download = `midjourney-${new Date().getTime()}.png`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    }
  },
  beforeDestroy() {
    this.stopPolling();
  }
}
</script>

<style lang="scss" scoped>
.mj-container {
  height: 100%;
  display: flex;
  background-color: #f7f7f7;
}

.left-panel {
  width: 340px;
  padding: 20px 12px;
  border-right: 1px solid #e4e4e4;
  background: white;
  display: flex;
  flex-direction: column;
  gap: 20px;
  overflow-y: auto;

  .page-title {
    font-size: 16px;
    font-weight: normal;
    color: #302e34;
    margin: 0;
  }
}

.right-panel {
  flex: 1;
  padding: 20px 12px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.input-section {
  flex-grow: 1;
  overflow: auto;
  display: flex;
  flex-direction: column;
  padding:6px;

  .prompt-input {
    margin-bottom: 20px;

    .custom-input {
      :deep(.el-textarea__inner) {
        border: none;
        border-radius: 8px;
        padding: 12px;
        font-size: 14px;
        line-height: 1.6;
        resize: none;
        background: #f5f7fa;
        color: #302e34;
        min-height: 120px !important;
        &:focus {
          background: white;
          box-shadow: 0 0 0 1px #7E4CE0;
        }
        &::placeholder {
          color: #999;
          line-height: 1.6;
        }
      }
    }
  }
}

.button-group {
  width: 100%;
  flex-shrink: 0;
  margin-top: 20px;
  display: flex;
  gap: 12px;

  .generate-btn {
    flex: 1;
    background: #7E4CE0;
    border-color: #7E4CE0;
    &:hover {
      background: darken(#7E4CE0, 5%);
    }
  }
}

.options-panel {
  margin: 0 0 16px 0;

  .option-group {
    margin: 0 0 16px 0;

    .option-title {
      font-size: 13px;
      color: #999;
      margin-bottom: 12px;
      padding-left: 4px;
    }

    .size-options,
    .style-options {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      gap: 8px;
      width: 100%;
      padding: 4px;
      margin-bottom: 16px;

      .size-option,
      .style-option {
        height: 32px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 16px;
        cursor: pointer;
        user-select: none;
        font-size: 13px;
        color: #666;
        background: #f5f7fa;
        transition: all 0.2s;
        padding: 0 16px;

        &:hover {
          background: #eef1f6;
        }

        &.is-active {
          background: #7E4CE0;
          color: white;
          font-weight: 500;
        }
      }
    }

    .style-options {
      grid-template-columns: repeat(2, 1fr);
    }
  }
}

.chat-window {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: white;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);

  .messages {
    flex: 1;
    overflow-y: auto;
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 16px;

    .message-item {
      max-width: 90%;

      &.assistant {
        align-self: center;
        background: #f5f7fa;
        padding: 8px 16px;
        border-radius: 16px;
        color: #666;
        font-size: 14px;
      }

      &.error {
        align-self: center;
        background: #fef0f0;
        padding: 8px 16px;
        border-radius: 16px;
        color: #f56c6c;
        font-size: 14px;
      }

      &.image {
        align-self: center;
        width: 100%;

        .image-container {
          position: relative;
          border-radius: 12px;
          overflow: hidden;
          background: #f5f7fa;
          box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);

          .el-image {
            width: 100%;
            display: block;
          }

          &:hover .image-actions {
            opacity: 1;
          }
        }

        .image-actions {
          position: absolute;
          bottom: 0;
          left: 0;
          right: 0;
          padding: 12px;
          background: linear-gradient(to top, rgba(0,0,0,0.7), transparent);
          opacity: 0;
          transition: opacity 0.3s;

          .action-buttons {
            display: flex;
            flex-direction: column;
            gap: 8px;

            .action-row {
              display: flex;
              justify-content: center;
              gap: 8px;

              .el-button {
                color: white;
                border-color: rgba(255, 255, 255, 0.3);
                background: rgba(0, 0, 0, 0.3);

                &:hover {
                  background: rgba(126, 76, 224, 0.7);
                  border-color: #7E4CE0;
                }
              }
            }
          }
        }

        .prompt-text {
          margin-top: 8px;
          font-size: 13px;
          color: #666;
          text-align: center;
          padding: 0 16px;
        }
      }
    }
  }
}

.empty-state {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #909399;
  padding: 40px;

  i {
    font-size: 48px;
    margin-bottom: 16px;
    color: #dcdfe6;
  }

  p {
    font-size: 14px;
    color: #909399;
    margin: 0;
  }
}

.image-placeholder {
  height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f5f7fa;
  color: #dcdfe6;

  i {
    font-size: 32px;
  }
}
</style>
